package com.squareup.picasso;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.drawable.BitmapDrawable;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;

import com.squareup.picasso.NetworkRequestHandler.ContentLengthException;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;

public final class Dispatcher {

    static final int REQUEST_SUBMIT = 1;
    static final int REQUEST_CANCEL = 2;
    static final int REQUEST_GCED = 3;
    static final int HUNTER_COMPLETE = 4;
    static final int HUNTER_RETRY = 5;
    static final int HUNTER_DECODE_FAILED = 6;
    static final int HUNTER_DELAY_NEXT_BATCH = 7;
    static final int HUNTER_BATCH_COMPLETE = 8;
    static final int NETWORK_STATE_CHANGE = 9;
    static final int AIRPLANE_MODE_CHANGE = 10;

    final class DispatcherHandler extends Handler {

        public DispatcherHandler(Looper looper) {
            super(looper);
        }

        public final void handleMessage(final Message message) {
            switch (message.what) {
                case 1:
                    Dispatcher.this.performSubmit((Action) message.obj, true);
                    break;
                case 2:
                    Action action = (Action) message.obj;
                    String key = action.key;
                    BitmapHunter bitmapHunter = hunterMap.get(key);
                    if (bitmapHunter != null) {
                        bitmapHunter.detach(action);
                        if (bitmapHunter.cancel()) {
                            hunterMap.remove(key);
                        }
                    }
                    if (pausedTags.contains(action.tag)) {
                        pausedActions.remove(action.getTarget());
                    }
                    failedActions.remove(action.getTarget());
                    break;
                case 4: {
                    BitmapHunter hunter = (BitmapHunter) message.obj;
                    if ((MemoryPolicy.shouldWriteToMemoryCache(hunter.d)) && ((hunter.result instanceof BitmapDrawable))) {
                        cache.set(hunter.key, ((BitmapDrawable) hunter.result).getBitmap());
                    }

                    hunterMap.remove(hunter.key);
                    batch(hunter);
                    break;
                }
                case 5: {
                    Dispatcher.this.performRetry((BitmapHunter) message.obj);
                    break;
                }
                case 6: {
                    Dispatcher.this.performError((BitmapHunter) message.obj);
                    break;
                }
                case 7: {
                    List<BitmapHunter> copy = new ArrayList(batch);
                    batch.clear();
                    mainThreadHandler.sendMessage(mainThreadHandler.obtainMessage(8, copy));
                    if (copy.isEmpty()) {
                        return;
                    }
                    copy.get(0);
                    break;
                }
                case 9: {
                    Dispatcher.this.performNetworkStateChange((NetworkInfo) message.obj);
                    break;
                }
                case 10: {
                    break;
                }
                case 11: {//performPauseTag
                    Object tag = message.obj;
                    if (!pausedTags.add(tag)) {
                        return;
                    }
                    Iterator<BitmapHunter> iterator = hunterMap.values().iterator();
                    do {
                        if (!iterator.hasNext()) {
                            return;
                        }

                        BitmapHunter hunter = iterator.next();
                        Action single = hunter.action;
                        List<Action> joined = hunter.actions;
                        boolean hasMultiple = joined != null && !joined.isEmpty();
                        if (single == null && !hasMultiple) {
                            continue;
                        } else {
                            if (single != null && (single.tag.equals(tag))) {
                                hunter.detach(single);
                                pausedActions.put(single.getTarget(), single);
                            }

                            if (hasMultiple) {
                                for (int i = joined.size() - 1; i >= 0; --i) {
                                    Action action1 = joined.get(i);
                                    if (action1.tag.equals(tag)) {
                                        hunter.detach(action1);
                                        pausedActions.put(action1.getTarget(), action1);
                                    }
                                }
                            }
                            if (hunter.cancel()) {
                                iterator.remove();
                            }
                        }
                    } while (true);
                }
                case 12: {//performResumeTag
                    Object tag2 = message.obj;
                    if (!pausedTags.remove(tag2)) {
                        return;
                    }

                    ArrayList<Action> batch = null;
                    Iterator<Action> iterator = pausedActions.values().iterator();
                    while (iterator.hasNext()) {
                        Action action1 = iterator.next();
                        if (!action1.tag.equals(tag2)) {
                            continue;
                        }

                        if (batch == null) {
                            batch = new ArrayList();
                        }

                        batch.add(action1);
                        iterator.remove();
                    }

                    if (batch == null) {
                        return;
                    }

                    mainThreadHandler.sendMessage(mainThreadHandler.obtainMessage(13, batch));
                    break;
                }
                default: {
                    Picasso.dispatcherHandler.post(new Runnable() {
                        @Override
                        public final void run() {
                            throw new AssertionError("Unknown handler message received: " + message.what);
                        }
                    });
                    break;
                }
            }
        }
    }

    final class DispatcherThread extends HandlerThread {
        DispatcherThread() {
            super("Picasso-Dispatcher", 10);
        }
    }

    final class NetworkBroadcastReceiver extends BroadcastReceiver {

        public final void onReceive(Context context, Intent intent) {
            if (intent != null) {
                String action = intent.getAction();
                if (!"android.intent.action.AIRPLANE_MODE".equals(action)) {
                    if (!"android.net.conn.CONNECTIVITY_CHANGE".equals(action)) {
                        return;
                    }
                    Dispatcher.this.handler.sendMessage(
                            Dispatcher.this.handler.obtainMessage(9,
                                    ((ConnectivityManager) Utils.getSystemService(context, "connectivity")
                                    ).getActiveNetworkInfo()));
                } else if (intent.hasExtra("state")) {
                    boolean airplaneMode = intent.getBooleanExtra("state", false);
                    Dispatcher.this.handler.sendMessage(Dispatcher.this.handler.obtainMessage(10, airplaneMode ? 1 : 0, 0));
                }
            }
        }
    }

    final Map<String, BitmapHunter> hunterMap;
    final Map<Object, Action> failedActions;
    final Map<Object, Action> pausedActions;
    final Set<Object> pausedTags;
    final Handler handler;
    final Handler mainThreadHandler;
    final Cache cache;
    final List<BitmapHunter> batch;
    private DispatcherThread dispatcherThread;
    private Context context;
    private BitmapDiskLruCache mBitmapDiskLruCache;
    private Stats stats;
    private NetworkBroadcastReceiver mNetworkBroadcastReceiver;
    private boolean scansNetworkChanges;

    Dispatcher(Context context, Handler mainThreadHandler, Cache cache, BitmapDiskLruCache bitmapDiskLruCache, Stats stats) {
        this.dispatcherThread = new DispatcherThread();
        this.dispatcherThread.start();
        Utils.flushStackLocalLeaks(this.dispatcherThread.getLooper());
        this.context = context;
        this.hunterMap = new LinkedHashMap();
        this.failedActions = new WeakHashMap();
        this.pausedActions = new WeakHashMap();
        this.pausedTags = new HashSet();
        this.handler = new DispatcherHandler(this.dispatcherThread.getLooper());
        this.mainThreadHandler = mainThreadHandler;
        this.cache = cache;
        this.mBitmapDiskLruCache = bitmapDiskLruCache;
        this.stats = stats;
        this.batch = new ArrayList(4);
        Utils.isAirplaneModeOn(this.context);
        this.scansNetworkChanges = Utils.hasPermission(context, "android.permission.ACCESS_NETWORK_STATE");
        this.mNetworkBroadcastReceiver = new NetworkBroadcastReceiver();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction("android.intent.action.AIRPLANE_MODE");
        if (scansNetworkChanges) {
            intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
        }
        context.registerReceiver((mNetworkBroadcastReceiver), intentFilter);
    }

    final void dispatchRetry(BitmapHunter hunter) {
        this.handler.sendMessageDelayed(this.handler.obtainMessage(5, hunter), 500L);
    }

    public final void cancel(Action action) {
        this.handler.sendMessage(this.handler.obtainMessage(REQUEST_CANCEL, action));
    }

    final void performNetworkStateChange(NetworkInfo networkInfo) {
        if (networkInfo != null && networkInfo.isConnected() && !this.failedActions.isEmpty()) {
            Iterator<Action> iterator = this.failedActions.values().iterator();
            while (iterator.hasNext()) {
                Action action = iterator.next();
                iterator.remove();
                this.performSubmit(action, false);
            }
        }
    }

    final void performSubmit(Action action, boolean dismissFailed) {
        if (this.pausedTags.contains(action.tag)) {
            this.pausedActions.put(action.getTarget(), action);
        } else {
            BitmapHunter hunter = this.hunterMap.get(action.key);
            if (hunter == null) {
                hunter = BitmapHunter.forRequest(action.picasso, this, this.cache, this.mBitmapDiskLruCache, this.stats, action);
                hunter.absRequest = Runnable2AbsRequestTransformer.transform(((Runnable) hunter));
                this.hunterMap.put(action.key, hunter);
                if (!dismissFailed) {
                    return;
                }
                this.failedActions.remove(action.getTarget());
            } else if (hunter.action == null) {
                hunter.action = action;
            } else {
                if (hunter.actions == null) {
                    hunter.actions = new ArrayList(3);
                }
                hunter.actions.add(action);
                Picasso.Priority priority = action.data.priority;
                if (priority.ordinal() <= hunter.priority.ordinal()) {
                    return;
                }
                hunter.priority = priority;
            }
        }
    }

    final void dispatchFailed(BitmapHunter bitmapHunter) {
        this.handler.sendMessage(this.handler.obtainMessage(6, bitmapHunter));
    }

    private void markForReplay(Action action) {
        Object target = action.getTarget();
        if (target != null) {
            action.willReplay = true;
            this.failedActions.put(target, action);
        }
    }

    final void performRetry(BitmapHunter bitmapHunter) {
        if (!bitmapHunter.isCancelled()) {
            NetworkInfo networkInfo = this.scansNetworkChanges
                    ? ((ConnectivityManager) Utils.getSystemService(this.context, "connectivity")).getActiveNetworkInfo()
                    : null;
            int hasConnectivity = networkInfo == null || !networkInfo.isConnected() ? 0 : 1;
            boolean hasRetryCount = bitmapHunter.retryCount > 0;
            boolean shouldRetry = false;
            if (hasRetryCount) {
                --bitmapHunter.retryCount;
                shouldRetry = bitmapHunter.requestHandler.shouldRetry(networkInfo);
            }

            boolean supportsReplay = bitmapHunter.requestHandler.supportsReplay();
            if (!shouldRetry) {
                boolean willReplay = this.scansNetworkChanges && supportsReplay;
                this.performError(bitmapHunter);
                if (willReplay) {
                    this.markForReplay(bitmapHunter);
                    return;
                } else {
                    return;
                }


            }

            if ((this.scansNetworkChanges) && hasConnectivity == 0) {
                this.performError(bitmapHunter);
                if (supportsReplay) {
                    this.markForReplay(bitmapHunter);
                } else {
                }

                return;
            }

            if ((bitmapHunter.exception instanceof ContentLengthException)) {
                bitmapHunter.errorResOd |= NetworkPolicy.NO_CACHE.index;
            }

            bitmapHunter.absRequest = Runnable2AbsRequestTransformer.transform(bitmapHunter);
        }
    }

    final void performError(BitmapHunter hunter) {
        this.hunterMap.remove(hunter.key);
        this.batch(hunter);
    }

    final void batch(BitmapHunter hunter) {
        if (!hunter.isCancelled()) {
            this.batch.add(hunter);
            if (!this.handler.hasMessages(7)) {
                this.handler.sendEmptyMessageDelayed(7, 200L);
            }
        }
    }

    private void markForReplay(BitmapHunter hunter) {
        Action action = hunter.action;
        if (action != null) {
            this.markForReplay(action);
        }

        List<Action> joined = hunter.actions;
        if (joined != null) {
            int size = joined.size();
            for (int i = 0; i < size; ++i) {
                this.markForReplay(joined.get(i));
            }
        }
    }
}

